home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 3: Developer Tools / Linux Cubed Series 3 - Developer Tools.iso / utils / file / managers / mc-3.2 / mc-3 / mc-3.2.1 / src / help.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-05-17  |  19.2 KB  |  804 lines

  1. /* Hypertext file browser.
  2.    Copyright (C) 1994, 1995 Miguel de Icaza.
  3.    Copyright (C) 1994, 1995 Janne Kukonlehto
  4.    
  5.    This program is free software; you can redistribute it and/or modify
  6.    it under the terms of the GNU General Public License as published by
  7.    the Free Software Foundation; either version 2 of the License, or
  8.    (at your option) any later version.
  9.    
  10.    This program is distributed in the hope that it will be useful,
  11.    but WITHOUT ANY WARRANTY; without even the implied warranty of
  12.    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13.    GNU General Public License for more details.
  14.  
  15.    You should have received a copy of the GNU General Public License
  16.    along with this program; if not, write to the Free Software
  17.    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  18.  
  19.    Implements the hypertext file viewer.
  20.    The hypertext file is a file that may have one or more nodes.  Each
  21.    node ends with a ^D character and starts with a bracket, then the
  22.    name of the node and then a closing bracket.
  23.  
  24.    Links in the hypertext file are specified like this: the text that
  25.    will be highlighted should have a leading ^A, then it comes the
  26.    text, then a ^B indicating that highlighting is done, then the name
  27.    of the node you want to link to and then a ^C.
  28.  
  29.    The file must contain a ^D at the beginning and at the end of the
  30.    file or the program will not be able to detect the end of file.
  31.  
  32.    Lazyness/widgeting attack: This file does use the dialog manager
  33.    and uses mainly the dialog to achieve the help work.  there is only
  34.    one specialized widget and it's only used to forward the mouse messages
  35.    to the appropiate routine.
  36.    
  37. */
  38.  
  39. #include <config.h>
  40. #include "tty.h"
  41. #include <stdio.h>
  42. #include <sys/types.h>
  43. #include <sys/stat.h>
  44. #include <malloc.h>
  45. #include <errno.h>
  46. #include "mad.h"
  47. #include "color.h"
  48. #include "util.h"
  49. #include "dialog.h"
  50. #include "win.h"
  51. #include "global.h"
  52. #include "mouse.h"
  53. #include "key.h"    /* For mi_getch() */
  54. #include "help.h"
  55. #include "layout.h"        /* keybar_visible */
  56.  
  57. #include "dlg.h"        /* For Dlg_head */
  58. #include "widget.h"        /* For Widget */
  59.  
  60. #ifndef USE_NCURSES
  61. #   define ACS_MAP(x) '*'
  62. #else
  63. #   ifndef ACS_MAP
  64. #       define ACS_MAP(x) acs_map [x]
  65. #   endif
  66. #endif
  67.  
  68. #define MAXLINKNAME 80
  69. #define HISTORY_SIZE 20
  70. #define HELP_WINDOW_WIDTH 62
  71.  
  72. /* "$Id: help.c,v 1.15 1995/02/21 19:06:03 miguel Exp $" */
  73.  
  74. static char *data;        /* Pointer to the loaded data file */
  75. static int help_lines = 18;    /* Lines in help viewer */
  76. static int  history_ptr;    /* For the history queue */
  77. static char *main;        /* The main node */
  78. static char *last_shown = 0;    /* Last byte shown in a screen */
  79. static int end_of_node = 0;    /* Flag: the last character of the node shown? */
  80. char *currentpoint, *startpoint;
  81. static char *selected_item;
  82.  
  83. /* The widget variables */
  84. static Dlg_head *whelp;
  85.  
  86. static struct {
  87.     char *page;            /* Pointer to the selected page */
  88.     char *link;            /* Pointer to the selected link */
  89. } history [HISTORY_SIZE];
  90.  
  91. /* Link areas for the mouse */
  92. typedef struct Link_Area {
  93.     int x1, y1, x2, y2;
  94.     char *link_name;
  95.     struct Link_Area *next;
  96. } Link_Area;
  97.  
  98. static Link_Area *link_area = NULL;
  99. static int inside_link_area = 0;
  100.  
  101. static int help_callback (struct Dlg_head *h, int id, int msg);
  102.  
  103. /* returns the position where text was found in the start buffer */
  104. /* or 0 if not found */
  105. char *search_string (char *start, char *text)
  106. {
  107.     char *d = text;
  108.     char *e = start;
  109.  
  110.     /* fmt sometimes replaces a space with a newline in the help file */
  111.     /* Replace the newlines in the link name with spaces to correct the situation */
  112.     while (*d){
  113.     if (*d == '\n')
  114.         *d = ' ';
  115.     d++;
  116.     }
  117.     /* Do search */
  118.     for (d = text; *e; e++){
  119.     if (*d == *e)
  120.         d++;
  121.     else
  122.         d = text;
  123.     if (!*d)
  124.         return e+1;
  125.     }
  126.     return 0;
  127. }
  128.  
  129. /* Searches text in the buffer pointed by start.  Search ends */
  130. /* if the CHAR_NODE_END is found in the text.  Returns 0 on failure */
  131. static char *search_string_node (char *start, char *text)
  132. {
  133.     char *d = text;
  134.     char *e = start;
  135.  
  136.     if (!start)
  137.     return 0;
  138.     
  139.     for (; *e && *e != CHAR_NODE_END; e++){
  140.     if (*d == *e)
  141.         d++;
  142.     else
  143.         d = text;
  144.     if (!*d)
  145.         return e+1;
  146.     }
  147.     return 0;
  148. }
  149.  
  150. /* Searches the_char in the buffer pointer by start and searches */
  151. /* it can search forward (direction = 1) or backward (direction = -1) */
  152. static char *search_char_node (char *start, char the_char, int direction)
  153. {
  154.     char *e;
  155.  
  156.     e = start;
  157.     
  158.     for (; *e && (*e != CHAR_NODE_END); e += direction){
  159.     if (*e == the_char)
  160.         return e;
  161.     }
  162.     return 0;
  163. }
  164.  
  165. /* Returns the new current pointer when moved lines lines */
  166. static char *move_forward2 (char *c, int lines)
  167. {
  168.     char *p;
  169.     int  line;
  170.  
  171.     currentpoint = c;
  172.     for (line = 0, p = currentpoint; *p && *p != CHAR_NODE_END; p++){
  173.     if (line == lines)
  174.         return currentpoint = p;
  175.     if (*p == '\n')
  176.         line++;
  177.     }
  178.     return currentpoint = c;
  179. }
  180.  
  181. static char *move_backward2 (char *c, int lines)
  182. {
  183.     char *p;
  184.     int line;
  185.  
  186.     currentpoint = c;
  187.     for (line = 0, p = currentpoint; *p && p >= data; p--){
  188.     if (*p == CHAR_NODE_END)
  189.     {
  190.         /* We reached the beginning of the node */
  191.         /* Skip the node headers */
  192.         while (*p != ']') p++;
  193.         return currentpoint = p + 2;
  194.     }
  195.     if (*(p - 1) == '\n')
  196.         line++;
  197.     if (line == lines)
  198.         return currentpoint = p;
  199.     }
  200.     return currentpoint = c;
  201. }
  202.  
  203. static void move_forward (int i)
  204. {
  205.     if (end_of_node)
  206.     return;
  207.     currentpoint = move_forward2 (currentpoint, i);
  208. }
  209.  
  210. static void move_backward (int i)
  211. {
  212.     currentpoint = move_backward2 (currentpoint, ++i);
  213. }
  214.  
  215. static void move_to_top (int dummy)
  216. {
  217.     while (currentpoint > data && *currentpoint != CHAR_NODE_END)
  218.     currentpoint--;
  219.     while (*currentpoint != ']')
  220.     currentpoint++;
  221.     currentpoint = currentpoint + 1;
  222.     selected_item = NULL;
  223. }
  224.  
  225. static void move_to_bottom (int dummy)
  226. {
  227.     while (*currentpoint && *currentpoint != CHAR_NODE_END)
  228.     currentpoint++;
  229.     currentpoint--;
  230.     move_backward (help_lines - 1);
  231. }
  232.  
  233. char *help_follow_link (char *start, char *selected_item)
  234. {
  235.     char link_name [MAXLINKNAME];
  236.     char *p;
  237.     int  i = 0;
  238.  
  239.     if (!selected_item)
  240.     return start;
  241.     
  242.     for (p = selected_item; *p && *p != CHAR_NODE_END && *p != CHAR_LINK_POINTER; p++)
  243.     ;
  244.     if (*p == CHAR_LINK_POINTER){
  245.     link_name [0] = '[';
  246.     for (i = 1; *p != CHAR_LINK_END && *p && *p != CHAR_NODE_END && i < MAXLINKNAME-3; )
  247.         link_name [i++] = *++p;
  248.     link_name [i-1] = ']';
  249.     link_name [i] = 0;
  250.     p = search_string (data, link_name);
  251.     if (p)
  252.         return p;
  253.     }
  254.     return " Help file format error\n\x4";    /*  */
  255. }
  256.  
  257. static char *select_next_link (char *start, char *current_link)
  258. {
  259.     char *p;
  260.  
  261.     if (!current_link)
  262.     return 0;
  263.  
  264.     p = search_string_node (current_link, STRING_LINK_END);
  265.     if (!p)
  266.     return NULL;
  267.     p = search_string_node (p, STRING_LINK_START);
  268.     if (!p)
  269.     return NULL;
  270.     return p - 1;
  271. }
  272.  
  273. static char *select_prev_link (char *start, char *current_link)
  274. {
  275.     char *p;
  276.  
  277.     if (!current_link)
  278.     return 0;
  279.     
  280.     p = current_link - 1;
  281.     if (p <= start)
  282.     return 0;
  283.     
  284.     p = search_char_node (p, CHAR_LINK_START, -1);
  285.     return p;
  286. }
  287.  
  288. static void start_link_area (int x, int y, char *link_name)
  289. {
  290.     Link_Area *new;
  291.  
  292.     if (inside_link_area)
  293.     message (0, " Warning ", " Internal bug: Double start of link area ");
  294.  
  295.     /* Allocate memory for a new link area */
  296.     new = (Link_Area*) xmalloc (sizeof (Link_Area), "Help, link_area");
  297.     new->next = link_area;
  298.     link_area = new;
  299.  
  300.     /* Save the beginning coordinates of the link area */
  301.     link_area->x1 = x;
  302.     link_area->y1 = y;
  303.  
  304.     /* Save the name of the destination anchor */
  305.     link_area->link_name = link_name;
  306.  
  307.     inside_link_area = 1;
  308. }
  309.  
  310. static void end_link_area (int x, int y)
  311. {
  312.     if (inside_link_area){
  313.     /* Save the end coordinates of the link area */
  314.     link_area->x2 = x;
  315.     link_area->y2 = y;
  316.  
  317.     inside_link_area = 0;
  318.     }
  319. }
  320.  
  321. static void clear_link_areas (void)
  322. {
  323.     Link_Area *current;
  324.  
  325.     while (link_area){
  326.     current = link_area;
  327.     link_area = current -> next;
  328.     free (current);
  329.     }
  330.     inside_link_area = 0;
  331. }
  332.  
  333. static void show (Dlg_head *h, char *paint_start)
  334. {
  335.     char *p;
  336.     int  col, line, c;
  337.     int  painting = 1;
  338.     int acs;            /* Flag: Alternate character set active? */
  339.     int repeat_paint;
  340.     int active_col, active_line;/* Active link position */
  341.  
  342.     do {
  343.     
  344.     line = col = acs = active_col = active_line = repeat_paint = 0;
  345.     
  346.     clear_link_areas ();
  347.     if (selected_item < paint_start)
  348.         selected_item = NULL;
  349.     
  350.     for (p = paint_start; *p != CHAR_NODE_END && line < help_lines; p++){
  351.         c = *p;
  352.         switch (c){
  353.         case CHAR_LINK_START:
  354.         if (selected_item == NULL)
  355.             selected_item = p;
  356.         if (p == selected_item){
  357.             attrset (HELP_SLINK_COLOR);
  358.  
  359.             /* Store the coordinates of the link */
  360.             active_col = col + 2;
  361.             active_line = line + 2;
  362.         }
  363.         else
  364.             attrset (HELP_LINK_COLOR);
  365.         start_link_area (col, line, p);
  366.         break;
  367.         case CHAR_LINK_POINTER:
  368.         painting = 0;
  369.         end_link_area (col - 1, line);
  370.         break;
  371.         case CHAR_LINK_END:
  372.         painting = 1;
  373.         attrset (HELP_NORMAL_COLOR);
  374.         break;
  375.         case CHAR_ALTERNATE:
  376.         acs = 1;
  377.         break;
  378.         case CHAR_NORMAL:
  379.         acs = 0;
  380.         break;
  381.         case CHAR_VERSION:
  382.         dlg_move (h, line+2, col+2);
  383.         addstr (VERSION);
  384.         col += strlen (VERSION);
  385.         break;
  386.         case CHAR_BOLD_ON:
  387.         attrset (HELP_BOLD_COLOR);
  388.         break;
  389.         case CHAR_ITALIC_ON:
  390.         attrset (HELP_ITALIC_COLOR);
  391.         break;
  392.         case CHAR_BOLD_OFF:
  393.         attrset (HELP_NORMAL_COLOR);
  394.         break;
  395.         case '\n':
  396.         line++;
  397.         col = 0;
  398.         break;
  399.         case '\t':
  400.         col = (col/8 + 1) * 8;
  401.         break;
  402.         case CHAR_MCLOGO:
  403.         case CHAR_TEXTONLY_START:
  404.         case CHAR_TEXTONLY_END:
  405.         break;
  406.         case CHAR_XONLY_START:
  407.         while (*p && *p != CHAR_NODE_END && *p != CHAR_XONLY_END)
  408.             p++;
  409.         if (*p == CHAR_NODE_END || !*p)
  410.             p--;
  411.         break;
  412.         default:
  413.         if (!painting)
  414.             continue;
  415.         if (col > HELP_WINDOW_WIDTH-1)
  416.             continue;
  417.         
  418.         dlg_move (h, line+2, col+2);
  419.         if (acs){
  420.             if (c == ' ' || c == '.')
  421.             addch (c);
  422.             else
  423. #ifndef HAVE_SLANG
  424.             addch (ACS_MAP(c));
  425. #else
  426.             SLsmg_draw_object (h->y + line + 2, h->x + col + 2, c);
  427. #endif            
  428.         } else
  429.             addch (c);
  430.         col++;
  431.         break;
  432.         }
  433.     }
  434.     last_shown = p;
  435.     end_of_node = line < help_lines;
  436.     attrset (HELP_NORMAL_COLOR);
  437.     if (selected_item >= last_shown){
  438.         if (link_area != NULL){
  439.         selected_item = link_area->link_name;
  440.         repeat_paint = 1;
  441.         }
  442.         else
  443.         selected_item = NULL;
  444.     }
  445.     } while (repeat_paint);
  446.  
  447.     /* Position the cursor over a nice link */
  448.     if (active_col)
  449.     dlg_move (h, active_line, active_col);
  450. }
  451.  
  452. static int help_event (Gpm_Event *event, Widget *w)
  453. {
  454.     Link_Area *current_area;
  455.  
  456.     if (! (event->type & GPM_UP))
  457.     return 0;
  458.  
  459.     /* The event is relative to the dialog window, adjust it: */
  460.     event->y -= 2;
  461.     
  462.     if (event->buttons & GPM_B_RIGHT){
  463.     currentpoint = startpoint = history [history_ptr].page;
  464.     selected_item = history [history_ptr].link;
  465.     history_ptr--;
  466.     if (history_ptr < 0)
  467.         history_ptr = HISTORY_SIZE-1;
  468.     
  469.     help_callback (w->parent, 0, DLG_DRAW);
  470.     return 0;
  471.     }
  472.  
  473.     /* Test whether the mouse click is inside one of the link areas */
  474.     current_area = link_area;
  475.     while (current_area)
  476.     {
  477.     /* Test one line link area */
  478.     if (event->y == current_area->y1 && event->x >= current_area->x1 &&
  479.         event->y == current_area->y2 && event->x <= current_area->x2)
  480.         break;
  481.     /* Test two line link area */
  482.     if (current_area->y1 + 1 == current_area->y2){
  483.         /* The first line */
  484.         if (event->y == current_area->y1 && event->x >= current_area->x1)
  485.         break;
  486.         /* The second line */
  487.         if (event->y == current_area->y2 && event->x <= current_area->x2)
  488.         break;
  489.     }
  490.     /* Mouse will not work with link areas of more than two lines */
  491.  
  492.     current_area = current_area -> next;
  493.     }
  494.  
  495.     /* Test whether a link area was found */
  496.     if (current_area){
  497.     /* The click was inside a link area -> follow the link */
  498.     history_ptr = (history_ptr+1) % HISTORY_SIZE;
  499.     history [history_ptr].page = currentpoint;
  500.     history [history_ptr].link = current_area->link_name;
  501.     currentpoint = startpoint = help_follow_link (currentpoint, current_area->link_name);
  502.     selected_item = NULL;
  503.     } else{
  504.     if (event->y < 0)
  505.         move_backward (help_lines - 1);
  506.     else if (event->y >= help_lines)
  507.         move_forward (help_lines - 1);
  508.     else if (event->y < help_lines/2)
  509.         move_backward (1);
  510.     else
  511.         move_forward (1);
  512.     }
  513.  
  514.     /* Show the new node */
  515.     help_callback (w->parent, 0, DLG_DRAW);
  516.  
  517.     return 0;
  518. }
  519.  
  520. /* show help */
  521. void help_help_cmd (Dlg_head *h)
  522. {
  523.     history_ptr = (history_ptr+1) % HISTORY_SIZE;
  524.     history [history_ptr].page = currentpoint;
  525.     history [history_ptr].link = selected_item;
  526.     currentpoint = startpoint = search_string (data, "[How to use help]") + 1;
  527.     selected_item = NULL;
  528. #ifndef HAVE_XVIEW    
  529.     help_callback (h, 0, DLG_DRAW);
  530. #endif    
  531. }
  532.  
  533. void help_index_cmd (Dlg_head *h)
  534. {
  535.     char *new_item;
  536.  
  537.     history_ptr = (history_ptr+1) % HISTORY_SIZE;
  538.     history [history_ptr].page = currentpoint;
  539.     history [history_ptr].link = selected_item;
  540.     currentpoint = startpoint = search_string (data, "[Help]") + 1;
  541.  
  542.     if (!(new_item = search_string (data, "[Contents]")))
  543.     message (1, " Error ", " Can't find node [Contents] in help file ");
  544.     else
  545.     currentpoint = startpoint = new_item + 1;
  546.     selected_item = NULL;
  547. #ifndef HAVE_XVIEW    
  548.     help_callback (h, 0, DLG_DRAW);
  549. #endif    
  550. }
  551.  
  552. static void quit_cmd (void *x)
  553. {
  554.     Dlg_head *h = (Dlg_head *) x;
  555.     
  556.     h->running = 0;
  557. }
  558.  
  559. static void prev_node_cmd (Dlg_head *h)
  560. {
  561.     currentpoint = startpoint = history [history_ptr].page;
  562.     selected_item = history [history_ptr].link;
  563.     history_ptr--;
  564.     if (history_ptr < 0)
  565.     history_ptr = HISTORY_SIZE-1;
  566.     
  567. #ifndef HAVE_XVIEW    
  568.     help_callback (h, 0, DLG_DRAW);
  569. #endif    
  570. }
  571.  
  572. static int md_callback (Dlg_head *h, Widget *w, int msg, int par)
  573. {
  574.     return default_proc (h, msg, par);
  575. }
  576.  
  577. static Widget *mousedispatch_new (int y, int x, int yl, int xl)
  578. {
  579.     Widget *w = xmalloc (sizeof (Widget), "disp_new");
  580.  
  581.     init_widget (w, y, x, yl, xl,
  582.          (callback_fn) md_callback, 0, (mouse_h)  help_event);
  583.  
  584.     return w;
  585. }
  586.  
  587. static int help_handle_key (struct Dlg_head *h, int c)
  588. {
  589.     char *new_item;
  590.  
  591.     if (c != KEY_UP && c != KEY_DOWN &&
  592.     check_movement_keys (c, 1, help_lines, currentpoint,
  593.                  (movefn) move_backward2,
  594.                  (movefn) move_forward2,
  595.                  (movefn) move_to_top,
  596.                  (movefn) move_to_bottom))
  597.     /* Nothing */;
  598.     else switch (c){
  599.     case 'l':
  600.     case KEY_LEFT:
  601.     prev_node_cmd (h);
  602.     break;
  603.     
  604.     case '\n':
  605.     case KEY_RIGHT:
  606.     /* follow link */
  607.     if (!selected_item){
  608. #ifdef WE_WANT_TO_GO_BACKWARD_ON_KEY_RIGHT
  609.         /* Is there any reason why the right key would take us
  610.          * backward if there are no links selected?, I agree
  611.          * with Torben than doing nothing in this case is better
  612.          */
  613.         /* If there are no links, go backward in history */
  614.         history_ptr--;
  615.         if (history_ptr < 0)
  616.         history_ptr = HISTORY_SIZE-1;
  617.         
  618.         currentpoint = startpoint = history [history_ptr].page;
  619.         selected_item   = history [history_ptr].link;
  620. #endif
  621.     } else {
  622.         history_ptr = (history_ptr+1) % HISTORY_SIZE;
  623.         history [history_ptr].page = currentpoint;
  624.         history [history_ptr].link = selected_item;
  625.         currentpoint = startpoint = help_follow_link (currentpoint, selected_item) + 1;
  626.     }
  627.     selected_item = NULL;
  628.     break;
  629.     
  630.     case KEY_DOWN:
  631.     case '\t':
  632.     /* select next link */
  633.     new_item = select_next_link (startpoint, selected_item);
  634.     if (new_item){
  635.         selected_item = new_item;
  636.         if (selected_item >= last_shown){
  637.         if (c == KEY_DOWN)
  638.             move_forward (1);
  639.         else
  640.             selected_item = NULL;
  641.         }
  642.     } else if (c == KEY_DOWN)
  643.         move_forward (1);
  644.     else
  645.         selected_item = NULL;
  646.     break;
  647.     
  648.     case KEY_UP:
  649.     case ALT ('\t'):
  650.     /* select previous link */
  651.     new_item = select_prev_link (startpoint, selected_item);
  652.     selected_item = new_item;
  653.     if (selected_item < currentpoint || selected_item >= last_shown){
  654.         if (c == KEY_UP)
  655.         move_backward (1);
  656.         else{
  657.         if (link_area != NULL)
  658.             selected_item = link_area->link_name;
  659.         else
  660.             selected_item = NULL;
  661.         }
  662.     }
  663.     break;
  664.     
  665.     case 'n':
  666.     /* Next node */
  667.     new_item = currentpoint;
  668.     while (*new_item && *new_item != CHAR_NODE_END)
  669.         new_item++;
  670.     if (*++new_item == '['){
  671.         while (*new_item != ']')
  672.         new_item++;
  673.         currentpoint = new_item + 2;
  674.         selected_item = NULL;
  675.     }
  676.     break;
  677.     
  678.     case 'p':
  679.     /* Previous node */
  680.     new_item = currentpoint;
  681.     while (new_item > data + 1 && *new_item != CHAR_NODE_END)
  682.         new_item--;
  683.     new_item--;
  684.     while (new_item > data && *new_item != CHAR_NODE_END)
  685.         new_item--;
  686.     while (*new_item != ']')
  687.         new_item++;
  688.     currentpoint = new_item + 2;
  689.     selected_item = NULL;
  690.     break;
  691.     
  692.     case 'c':
  693.     help_index_cmd (h);
  694.     break;
  695.     
  696.     case ESC_CHAR:
  697.     case XCTRL('g'):
  698.     h->running = 0;
  699.     break;
  700.  
  701.     default:
  702.     return 0;
  703.         
  704.     }
  705.     help_callback (h, 0, DLG_DRAW);
  706.     return 1;
  707. }
  708.  
  709. static int help_callback (struct Dlg_head *h, int id, int msg)
  710. {
  711.     switch (msg){
  712.     case DLG_DRAW:
  713.     attrset (HELP_NORMAL_COLOR);
  714.     dlg_erase (h);
  715.     draw_box (h, 1, 1, help_lines+2, HELP_WINDOW_WIDTH+2);
  716.     attrset (COLOR_HOT_NORMAL);
  717.     dlg_move (h, 1, (HELP_WINDOW_WIDTH - 1) / 2);
  718.     addstr (" Help ");
  719.     attrset (HELP_NORMAL_COLOR);
  720.     show (h, currentpoint);
  721.     break;
  722.  
  723.     case DLG_KEY:
  724.     return help_handle_key (h, id);
  725.     }
  726.     return 0;
  727. }
  728.  
  729. void interactive_display_finish (void)
  730. {
  731.     clear_link_areas ();
  732.     free (data);
  733. }
  734.  
  735. void interactive_display (char *filename, char *node)
  736. {
  737.     WButtonBar *help_bar;
  738.     Widget     *md;
  739.     
  740.     if ((data = load_file (filename)) == 0){
  741.     message (1, " Error ", " Can't open file %s \n %s ",
  742.          filename, unix_error_string (errno));
  743.     return;
  744.     }
  745.     if (!(main = search_string (data, node))){
  746.     message (1, " Error ", " Can't find node %s in help file ", node);
  747.     return;
  748.     }
  749.  
  750. #ifndef HAVE_X
  751.     if (help_lines > LINES - 4)
  752.     help_lines = LINES - 4;
  753.  
  754.     whelp = create_dlg (0, 0, help_lines+4, HELP_WINDOW_WIDTH+4, dialog_colors,
  755.             help_callback, "[Help]", "help", DLG_TRYUP|DLG_CENTER);
  756.  
  757.     /* allow us to process the tab key */
  758.     whelp->raw = 1;
  759.  
  760. #endif    
  761.     selected_item = search_string_node (main, STRING_LINK_START) - 1;
  762.     currentpoint = startpoint = main + 1;
  763.  
  764.     for (history_ptr = HISTORY_SIZE; history_ptr;){
  765.     history_ptr--;
  766.     history [history_ptr].page = currentpoint;
  767.     history [history_ptr].link = selected_item;
  768.     }
  769.  
  770. #ifndef HAVE_X
  771.     help_bar = buttonbar_new (keybar_visible);
  772.     help_bar->widget.y -= whelp->y;
  773.     help_bar->widget.x -= whelp->x;
  774.     
  775.     md       = mousedispatch_new (1, 1, help_lines, HELP_WINDOW_WIDTH-2);
  776.     
  777.     add_widget (whelp, help_bar);
  778.     add_widget (whelp, md);
  779.  
  780.     define_label_data (whelp, (Widget *)NULL, 1, "Help",
  781.                (buttonbarfn) help_help_cmd, whelp);
  782.     define_label_data (whelp, (Widget *)NULL, 2, "Index",
  783.                (buttonbarfn) help_index_cmd,whelp);
  784.     define_label_data (whelp, (Widget *)NULL, 3, "Prev",
  785.                (buttonbarfn) prev_node_cmd, whelp);
  786.     define_label (whelp, (Widget *) NULL, 4, "", 0);
  787.     define_label (whelp, (Widget *) NULL, 5, "", 0);
  788.     define_label (whelp, (Widget *) NULL, 6, "", 0);
  789.     define_label (whelp, (Widget *) NULL, 7, "", 0);
  790.     define_label (whelp, (Widget *) NULL, 8, "", 0);
  791.     define_label (whelp, (Widget *) NULL, 9, "", 0);
  792.     define_label_data (whelp, (Widget *) NULL, 10, "Quit", quit_cmd, whelp);
  793.  
  794.     run_dlg (whelp);
  795.     interactive_display_finish ();
  796.     destroy_dlg (whelp);
  797. #else
  798.     x_interactive_display ();
  799. #endif
  800. }
  801.  
  802.  
  803.  
  804.